package net.zoneland.knowledge.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.common.collect.Streams;
import net.zoneland.knowledge.cache.RedisCacheUtil;
import net.zoneland.knowledge.constant.BizConstant;
import net.zoneland.knowledge.constant.Constants;
import net.zoneland.knowledge.controller.util.UserSelectItemUtils;
import net.zoneland.knowledge.dao.WorkApplyInfoMapper;
import net.zoneland.knowledge.enums.WorkStatusEnum;
import net.zoneland.knowledge.exceptions.WorkApplyException;
import net.zoneland.knowledge.model.LoginUserPojo;
import net.zoneland.knowledge.model.WorkApplyInfo;
import net.zoneland.knowledge.model.WorkApproveOpinion;
import net.zoneland.knowledge.model.WorkSubTaskInfo;
import net.zoneland.knowledge.service.UniFlowService;
import net.zoneland.knowledge.service.bean.ResultInfo;
import net.zoneland.uniflow.client.*;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 智办工单处理工具类.
 *
 * @author zmq
 * @Date 2022/8/15 15:10
 */
public final class WorkApplyOperationUtils {
    /**
     * 日志.
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(WorkApplyOperationUtils.class);

    /**
     * 自动节点处理人.
     */
    public static final UserInfo AUTO_NODE_HANDLER = new UserInfo("admin", "系统用户");

    /**
     * 自动节点处理人集合.
     */
    public static final UserInfo[] AUTO_NODE_HANDLERS = new UserInfo[]{
            AUTO_NODE_HANDLER
    };

    /**
     * 待办状态的集合.
     */
    public static final int[] READY_STATUS = new int[]{TaskObject.STATE_READY};

    /**
     * 待办\挂起状态的集合.
     */
    protected static final int[] READY_OR_SUSPENDED_STATUS = new int[]{TaskObject.STATE_READY, TaskObject.STATE_SUSPENDED};

    /**
     * 挂起状态的集合.
     */
    protected static final int[] SUSPENDED_STATUS = new int[]{TaskObject.STATE_SUSPENDED};

    /**
     * 创建子流程的扩展参数map.
     */
    private static final Map<String, String> SUB_FLOW_EXTENDS_DATA_MAP = Maps.newHashMap();

    static {
        SUB_FLOW_EXTENDS_DATA_MAP.put("noSubFlow", "false");
    }

    private static final int PAGE_SIZE = 200;

    /**
     * 创建子流程的扩展参数.
     */
    public static final Map<String, String> CREATE_SUB_FLOW_EXTENDS_DATA = MapUtils.unmodifiableMap(SUB_FLOW_EXTENDS_DATA_MAP);

    /**
     * 不创建子流程的扩展参数map.
     */
    private static final Map<String, String> NO_SUB_FLOW_EXTENDS_DATA_MAP = Maps.newHashMap();

    static {
        NO_SUB_FLOW_EXTENDS_DATA_MAP.put("noSubFlow", "true");
    }

    /**
     * 不创建子流程的扩展参数.
     */
    public static final Map<String, String> NO_SUB_FLOW_EXTENDS_DATA = MapUtils.unmodifiableMap(NO_SUB_FLOW_EXTENDS_DATA_MAP);

    /**
     * 确认环节的节点编号.
     */
    protected static final Set<String> CONFIRM_NODE_IDS = Sets.newHashSet(WorkStatusEnum.RESPONDER_APPROVE.getValue(),
            WorkStatusEnum.SUB_ORG_USER_CONFIRM.getValue());

    /**
     * 子流程系统环节的节点编号.
     */
    protected static final Set<String> SUB_TASK_NODE_IDS = Sets.newHashSet(WorkStatusEnum.CREATE_SUB_FLOW.getValue(),
            WorkStatusEnum.SUB_CREATE_SUB_FLOW.getValue());

    /**
     * 私有构造.
     */
    private WorkApplyOperationUtils() {

    }

    /**
     * 获取上报后父流程的下一个节点状态.
     *
     * @param info 工单信息
     * @return 提交状态
     */
    public static WorkStatusEnum getReportConfirmStatus(final WorkApplyInfo info) {
        boolean isMainFlow = StringUtils.isBlank(info.getParentId());
        return isMainFlow ? getNextSubmitStatus(WorkStatusEnum.CREATE_SUB_FLOW)
                : getNextSubmitStatus(WorkStatusEnum.SUB_CREATE_SUB_FLOW);
    }


    /**
     * 获取提交决策的下一节点状态.
     *
     * @param status 当前状态
     * @return 提交后下一决策状态
     */
    public static WorkStatusEnum getNextSubmitStatus(final WorkStatusEnum status) {
        WorkStatusEnum nextStatus = null;
        switch (status) {
            case DRAFT:
                nextStatus = WorkStatusEnum.DEPT_ADMIN_APPROVE;
                break;
            case DEPT_ADMIN_APPROVE:
                nextStatus = WorkStatusEnum.CREATE_SUB_FLOW;
                break;
            case CREATE_SUB_FLOW:
                nextStatus = WorkStatusEnum.RESPONDER_APPROVE;
                break;
            case RESPONDER_APPROVE:
            case SUB_CREATOR_CONFIRM:
                nextStatus = WorkStatusEnum.END;
                break;
            case SUB_ORG_USER_HANDLE:
            case SUB_ORG_USER_CONFIRM:
                nextStatus = WorkStatusEnum.SUB_CREATOR_CONFIRM;
                break;
            case SUB_CREATE_SUB_FLOW:
                nextStatus = WorkStatusEnum.SUB_ORG_USER_CONFIRM;
                break;
            default:
                break;
        }
        return nextStatus;
    }

    /**
     * 获取工单号.
     *
     * @param info 工单信息对象
     * @return uniflow工单号
     */
    public static String getUniflowApplyId(final WorkApplyInfo info) {
        if (StringUtils.equals(info.getFlowType(), BizConstant.CHAPTER_APPLY_PROCESS_CODE)
            || StringUtils.equals(info.getFlowType(), BizConstant.PARTY_BRANCH_PROCESS_CODE)
            || StringUtils.equals(info.getFlowType(), BizConstant.PARTY_COMMITTEE_PROCESS_CODE)) {
            return info.getApplyId();
        }
        if (StringUtils.isBlank(info.getParentId())) {
            return String.format("%s-%s", BizConstant.WISDOM_MAIN_PROCESS_CODE, info.getId());
        }
        return String.format("%s-%s", BizConstant.WISDOM_SUB_FLOW_PROCESS_CODE, info.getId());
    }

    /**
     * 转换用户.
     *
     * @param user 用户
     * @return uniflow对应用户
     */
    public static UserInfo convertUserInfo(final LoginUserPojo user) {
        return new UserInfo(user.getUserID(), user.getUserName());
    }

    /**
     * 终止删除流程.
     *
     * @param uniFlowService uniflow接口
     * @param tasks          任务集合
     * @param user           操作用户
     */
    public static void endSubFlow(final UniFlowService uniFlowService,
                                  final List<TaskObject> tasks, final LoginUserPojo user) {
        if (CollectionUtils.isNotEmpty(tasks)) {
            Set<String> piids = tasks.stream().map(TaskObject::getPiid).collect(Collectors.toSet());
            for (final String piid : piids) {
                ResultInfo resultInfo = uniFlowService
                        .deleteProcess(piid, new UserInfo(user.getUserID(), user.getUserName()), "事务异常回滚");
                if (resultInfo == null || resultInfo.isResult()) {
                    LOGGER.error("============当前终止流程异常，需要运维人员手工处理，流程piid：{}, 原因：{}",
                            piid, resultInfo != null ? resultInfo.getInfo() : "返回结果为空！");
                }
            }
        }
    }

    /**
     * 完成拟稿人确认任务.
     *
     * @param parentApply    工单
     * @param opinion        操作意见
     * @param uniFlowService ucc业务接口
     * @return 任务集合
     */
    public static List<TaskObject> completeUniflowConfirm(final WorkApplyInfo parentApply,
                                                          final String opinion, final UniFlowService uniFlowService) {
        TaskQueryParam queryParam = new TaskQueryParam();
        queryParam.setStates(new int[]{TaskObject.STATE_READY, TaskObject.STATE_SUSPENDED});
        queryParam.setApplyId(WorkApplyOperationUtils.getUniflowApplyId(parentApply));
        queryParam.setIncludeNodes(new String[]{WorkStatusEnum.CREATE_SUB_FLOW.getValue(),
                WorkStatusEnum.SUB_CREATE_SUB_FLOW.getValue(), WorkStatusEnum.RESPONDER_APPROVE.getValue(),
                WorkStatusEnum.SUB_ORG_USER_CONFIRM.getValue(),
        });
        ResultInfo resultInfo = uniFlowService.queryTasksByPage(queryParam, 1, 10);
        Preconditions.checkArgument(resultInfo != null && resultInfo.isResult(),
                "查询创建子流程节点的待办任务异常，id：" + parentApply.getId());
        TaskPageObject taskPage = (TaskPageObject) resultInfo.getData();
        Preconditions.checkArgument(taskPage != null && taskPage.getTaskObjects().length > 0,
                "未查询到创建子流程节点的待办任务，id：" + parentApply.getId());
        return dealUniflowTask(parentApply, opinion, uniFlowService, taskPage);
    }

    /**
     * 处理ucc任务.
     *
     * @param parentApply    工单
     * @param opinion        意见
     * @param uniFlowService ucc接口
     * @param taskPage       任务列表
     * @return 任务集合
     */
    private static List<TaskObject> dealUniflowTask(final WorkApplyInfo parentApply, final String opinion,
                                                    final UniFlowService uniFlowService, final TaskPageObject taskPage) {
        final List<TaskObject> res = Lists.newArrayList();
        if (parentApply == null) {
            return res;
        }
        try {
            for (TaskObject task : taskPage.getTaskObjects()) {
                ResultInfo resInfo = null;
                if (CONFIRM_NODE_IDS.contains(task.getNodeId()) && task.getState() == TaskObject.STATE_SUSPENDED) {
                    //如果是挂起，则需要恢复
                    resInfo = uniFlowService.resumeTask(task.getTiid());
                } else if (SUB_TASK_NODE_IDS.contains(task.getNodeId()) && task.getState() == TaskObject.STATE_READY) {
                    //如果是待办，则需要提交
                    resInfo = uniFlowService.completeTask(task.getTiid(), WorkApplyOperationUtils.AUTO_NODE_HANDLER,
                            DecisionObject.DECISION_SUBMIT, "系统提交", opinion, parentApply.getStatus().getValue(),
                            new UserInfo[]{new UserInfo(parentApply.getHandlerUid(), parentApply.getHandlerName())},
                            null, null);
                }
                if (resInfo != null) {
                    Preconditions.checkArgument(resInfo.isResult(),
                            "完成任务（节点：创建子流程）失败， tiid：" + task.getTiid()
                                    + "，异常信息：" + resInfo.getInfo());
                    if (resInfo.getData() != null) {
                        CollectionUtils.addAll(res, (TaskObject[]) resInfo.getData());
                    }
                }
            }
        } catch (Exception e) {
            rollbackTasks(uniFlowService, res);
            throw new WorkApplyException("完成父任务创建子流程节点待办任务失败，当前工单id:" + parentApply.getId(), e);
        }
        return res;
    }

    /**
     * 对于父流程的一些已完成的任务，应该要回退.
     *
     * @param uniFlowService ucc接口
     * @param tasks          任务集合
     */
    public static void rollbackTasks(final UniFlowService uniFlowService, final List<TaskObject> tasks) {
        if (CollectionUtils.isEmpty(tasks)) {
            return;
        }
        // 对于父流程的一些已完成的任务，应该要回退
        for (TaskObject task : tasks) {
            try {
                uniFlowService.revokeTask(task.getTiid(), "系统事务回滚！");
            } catch (Exception e) {
                LOGGER.error("撤回任务失败，tiid:{}", task.getTiid(), e);
            }
        }
    }

    /**
     * 查询特定节点特定状态的任务信息.
     *
     * @param uniFlowService ucc接口
     * @param owner          拥有者
     * @param info           工单信息
     * @param nodes          节点集合
     * @param taskStatus     状态集合
     * @return 任务集合
     */
    public static TaskObject[] queryTask(final UniFlowService uniFlowService, final String owner,
                                         final WorkApplyInfo info, final String[] nodes,
                                         final int[] taskStatus) {
        final TaskQueryParam queryParam = new TaskQueryParam();
        queryParam.setStates(taskStatus);
        queryParam.setApplyId(WorkApplyOperationUtils.getUniflowApplyId(info));
        queryParam.setOwner(owner);
        queryParam.setIncludeNodes(nodes);
        final ResultInfo resultInfo = uniFlowService.queryTasksByPage(queryParam, 1, PAGE_SIZE);
        Preconditions.checkArgument(resultInfo != null && resultInfo.isResult(), "uniflow查询任务信息失败!");
        return resultInfo.getData() != null ? ((TaskPageObject) resultInfo.getData()).getTaskObjects() : null;
    }

    /**
     * 完成确认节点的任务.
     * <p>
     * 责任人确认确认环节的待办.
     * </p>
     *
     * @param uniFlowService ucc业务接口
     * @param info           工单
     * @param taskId         任务id
     * @param opinion        意见
     * @param user           操作用户
     * @param allFinish      是否全部完成
     */
    public static TaskObject[] finishConfirmTask(final UniFlowService uniFlowService, final WorkApplyInfo info,
                                                 final String taskId, final String opinion,
                                                 final LoginUserPojo user, final boolean allFinish) {
        ResultInfo resultInfo = null;
        if (allFinish) {
            //完成当前任务到拟稿人确认
            resultInfo = uniFlowService.completeTask(taskId, convertUserInfo(user),
                    DecisionObject.DECISION_SUBMIT, "系统提交", opinion,
                    info.getStatus().getValue(),
                    new UserInfo[]{new UserInfo(info.getCreatorUid(), info.getCreatorName())},
                    null, null);
        } else {
            //挂起当前任务
            resultInfo = uniFlowService.suspendTask(taskId);
        }
        Preconditions.checkArgument(resultInfo != null && resultInfo.isResult(),
                "责任人确认环节提交的待办异常，id:" + info.getId());
        return resultInfo.getData() != null ? (TaskObject[]) resultInfo.getData() : null;
    }


    /**
     * 构造 审批意见.
     *
     * @param rejectReason 退回原因
     * @param user         用户
     * @param info         工单信息
     * @param decision     决策名称
     * @param nodeId       审批节点
     * @return 审批意见
     */
    public static WorkApproveOpinion buildApproveOpinionWithNodeId(final String rejectReason, final LoginUserPojo user,
                                                                   final WorkApplyInfo info, final String decision,
                                                                   final String nodeId) {
        final WorkApproveOpinion opinion = new WorkApproveOpinion();
        opinion.setApproveTime(DateTime.now().toDate());
        opinion.setApproveName(user.getUserName());
        opinion.setApproveUid(user.getUserID());
        opinion.setDecision(decision);
        opinion.setDeptDn(user.getDepartmentDN());
        opinion.setDeptName(user.getDeptName());
        opinion.setId(UUID.randomUUID().toString());
        opinion.setOpinion(rejectReason);
        opinion.setWorkApplyId(info.getId());
        opinion.setNodeId(nodeId);
        if (StringUtils.isNotBlank(info.getCopySubmit())) {
            final String ids = JSON.parseArray(info.getCopySubmit()).stream().map(item -> {
                final JSONObject jsonObject = JSON.parseObject(String.valueOf(item));
                return jsonObject.get("id").toString();
            }).collect(Collectors.joining(","));
            opinion.setCopySubmitUid(StringUtils.isBlank(ids) ? null : ids);
            final String labels = JSON.parseArray(info.getCopySubmit()).stream().map(item -> {
                final JSONObject jsonObject = JSON.parseObject(String.valueOf(item));
                return jsonObject.get("label").toString();
            }).collect(Collectors.joining(","));
            opinion.setCopySubmitName(StringUtils.isBlank(labels) ? null : labels);
        }
        return opinion;
    }

    public static WorkApproveOpinion buildApproveOpinionWithNodeIdNew(final String rejectReason, final LoginUserPojo user,
                                                                      final WorkApplyInfo info, final String decision,
                                                                      final String nodeId,final String status,final String taskId) {
        WorkApproveOpinion opinion = buildApproveOpinionWithNodeId(rejectReason, user, info, decision, nodeId);
        opinion.setWorkStatus(status);
        opinion.setSubTaskId(taskId);
        return opinion;
    }



    /**
     * 构造 审批意见.
     *
     * @param rejectReason 退回原因
     * @param user         用户
     * @param info         工单信息
     * @param decision     决策名称
     * @return 审批意见
     */
    public static WorkApproveOpinion buildApproveOpinion(final String rejectReason, final LoginUserPojo user,
                                                         final WorkApplyInfo info, final String decision) {
        return buildApproveOpinionWithNodeId(rejectReason, user, info, decision, null);
    }

    public static WorkApproveOpinion buildApproveOpinionNew(final String rejectReason, final LoginUserPojo user,
                                                            final WorkApplyInfo info, final String decision,
                                                            final String status) {
        return buildApproveOpinionWithNodeIdNew(rejectReason, user, info, decision, null,status,null);
    }

    public static WorkApproveOpinion buildApproveOpinionTask(final String rejectReason, final LoginUserPojo user,
                                                             final String applyId, final String decision,
                                                             final String status, final String taskId,final String nodeId) {
        WorkApplyInfo info = new WorkApplyInfo();
        info.setId(applyId);
        return buildApproveOpinionWithNodeIdNew(rejectReason, user, info, decision, nodeId,status,taskId);
    }


    /**
     * 责任人确认环节提交：更新子工单状态和任务信息.
     *
     * @param workApplyInfoMapper    数据接口
     * @param uniFlowService         ucc接口
     * @param needFinishSubApplyList 待更新状态子工单
     * @param opinion                意见
     * @param user                   用户
     * @return 任务集合
     */
    public static List<TaskObject> finishConfirmSubTask(WorkApplyInfoMapper workApplyInfoMapper,
                                                        UniFlowService uniFlowService,
                                                        List<WorkApplyInfo> needFinishSubApplyList,
                                                        String opinion, LoginUserPojo user) {
        List<TaskObject> res = Lists.newArrayList();
        if (CollectionUtils.isEmpty(needFinishSubApplyList)) {
            return res;
        }
        try {
            for (final WorkApplyInfo subApplyInfo : needFinishSubApplyList) {
                subApplyInfo.setStatus(WorkStatusEnum.END);
                subApplyInfo.setHandlerUid(null);
                subApplyInfo.setHandlerName(null);
                subApplyInfo.setUpdateTime(DateTime.now().toDate());
                workApplyInfoMapper.updateWorkApplyInfo(subApplyInfo);
//                workApplyInfoMapper.insertWorkApproveOpinion(buildApproveOpinion(opinion, user, subApplyInfo, "提交"));
                //对挂起的uniflow任务恢复并退回
                List<TaskObject> tasks = finishCreatorConfirmTasks(uniFlowService, subApplyInfo, null,
                        opinion, user, DecisionObject.DECISION_SUBMIT, "系统提交");
                if (CollectionUtils.isNotEmpty(tasks)) {
                    CollectionUtils.addAll(res, tasks.iterator());
                }
            }
        } catch (Exception e) {
            LOGGER.error("责任人确认环节提交：更新子工单状态和任务信息失败！", e);
            rollbackTasks(uniFlowService, res);
        }
        return res;
    }

    /**
     * 将子流程的任务退回到拟稿人确认前的一个环节.
     *
     * @param workApplyInfoMapper 工单数据接口
     * @param uniFlowService      ucc业务接口
     * @param subApplyList        子工单信息
     * @param opinion             意见
     * @param user                操作用户
     * @return 任务集合
     */
    public static List<TaskObject> rejectSubTasksToPreConfirmNode(final WorkApplyInfoMapper workApplyInfoMapper,
                                                                  final UniFlowService uniFlowService,
                                                                  final List<WorkApplyInfo> subApplyList,
                                                                  final String opinion, final LoginUserPojo user) {
        Preconditions.checkArgument(CollectionUtils.isNotEmpty(subApplyList), "当前工单的子任务为空！");
        List<TaskObject> res = Lists.newArrayList();
        for (final WorkApplyInfo subApplyInfo : subApplyList) {
            WorkStatusEnum oldStatus = subApplyInfo.getStatus();
            if (oldStatus != WorkStatusEnum.SUB_CREATOR_CONFIRM && oldStatus != WorkStatusEnum.END) {
                continue;
            }
            //更新分任务对应工单信息
            subApplyInfo.setUpdateTime(DateTime.now().toDate());
            final UserInfo[] subTaskHandlers = new UserInfo[]{
                    new UserInfo(subApplyInfo.getAssignUserId(), subApplyInfo.getAssignUserName())};
            Preconditions.checkArgument(ArrayUtils.isNotEmpty(subTaskHandlers), "对应分任务的处理人为空！");
            subApplyInfo.setHandlerUid(Stream.of(subTaskHandlers).map(UserInfo::getUserId)
                    .collect(Collectors.joining(";")));
            subApplyInfo.setHandlerName(Stream.of(subTaskHandlers).map(UserInfo::getUserName)
                    .collect(Collectors.joining(";")));
            subApplyInfo.setStatus(subApplyInfo.isDispatched() ? WorkStatusEnum.SUB_ORG_USER_CONFIRM
                    : WorkStatusEnum.SUB_ORG_USER_HANDLE);
            workApplyInfoMapper.updateWorkApplyInfo(subApplyInfo);
            workApplyInfoMapper.insertWorkApproveOpinion(WorkApplyOperationUtils
                    .buildApproveOpinion(opinion, user, subApplyInfo, "退回"));

            //对挂起的uniflow任务恢复并退回
            List<TaskObject> tasks = null;
            if (oldStatus == WorkStatusEnum.END) {
                //如果当前流程已经结束，则需要恢复流程到特定节点
                tasks = reliveProcessForSubFlow(uniFlowService, subApplyInfo, subTaskHandlers, opinion, user);
            } else {
                //如果当前流程在创建人确认，则直接执行退回操作
                tasks = finishCreatorConfirmTasks(uniFlowService, subApplyInfo, subTaskHandlers, opinion, user,
                        DecisionObject.DECISION_NO, "系统退回");
            }
            if (CollectionUtils.isNotEmpty(tasks)) {
                CollectionUtils.addAll(res, tasks.iterator());
            }
        }
        return res;
    }

    /**
     * 复活分任务流程到组织人员办理/组织人员确认节点.
     *
     * @param uniFlowService  ucc业务接口
     * @param subApplyInfo    子工单
     * @param subTaskHandlers 处理人
     * @param opinion         意见
     * @param user            当前处理人
     * @return 任务集合
     */
    private static List<TaskObject> reliveProcessForSubFlow(final UniFlowService uniFlowService,
                                                            final WorkApplyInfo subApplyInfo,
                                                            final UserInfo[] subTaskHandlers, final String opinion,
                                                            final LoginUserPojo user) {
        ProcessQueryParam param = new ProcessQueryParam();
        param.setBusinessProcesses(new String[]{BizConstant.WISDOM_SUB_FLOW_PROCESS_CODE});
        String applyId = getUniflowApplyId(subApplyInfo);
        param.setApplyId(applyId);
        ResultInfo resultInfo = uniFlowService.queryProcessInstances(param);
        Preconditions.checkNotNull(resultInfo, "查询流程实例异常！applyId:" + applyId);
        Preconditions.checkArgument(resultInfo.isResult(), "查询流程实例" + applyId + "异常：" + resultInfo.getInfo());
        Object data = resultInfo.getData();
        Preconditions.checkNotNull(data, "查询流程实例为空！applyId:" + applyId);
        ProcessObject[] processes = (ProcessObject[]) data;
        resultInfo = uniFlowService.syncReliveProcess(processes[0].getPiid(), subApplyInfo.getStatus().getValue(),
                subTaskHandlers, convertUserInfo(user), opinion);
        Preconditions.checkNotNull(resultInfo, "复活流程实例异常！applyId:" + applyId);
        Preconditions.checkArgument(resultInfo.isResult(), "复活流程实例" + applyId + "异常：" + resultInfo.getInfo());
        data = resultInfo.getData();
        if (data != null) {
            return Lists.newArrayList((TaskObject[]) data);
        }
        return Lists.newArrayList();
    }

    /**
     * 对拟稿人确认环节挂起的uniflow任务恢复并提交/退回.
     *
     * @param uniFlowService   ucc业务接口
     * @param subApplyInfo     工单信息
     * @param nextTaskHandlers 下一节点处理人
     * @param opinion          意见
     * @param user             操作用户
     * @param decision         决策
     * @param option           决策说明
     */
    private static List<TaskObject> finishCreatorConfirmTasks(UniFlowService uniFlowService, WorkApplyInfo subApplyInfo,
                                                              UserInfo[] nextTaskHandlers, String opinion, LoginUserPojo user,
                                                              String decision, String option) {
        List<TaskObject> res = Lists.newArrayList();
        TaskObject[] tasks = queryTask(uniFlowService, subApplyInfo.getCreatorUid(), subApplyInfo,
                new String[]{WorkStatusEnum.SUB_CREATOR_CONFIRM.getValue(), WorkStatusEnum.SUB_CREATOR_CONFIRM.getValue()},
                SUSPENDED_STATUS);
        for (TaskObject task : tasks) {
            //先恢复待办
            uniFlowService.resumeTask(task.getTiid());
            //完成任务
            ResultInfo resultInfo = uniFlowService.completeTask(task.getTiid(), convertUserInfo(user),
                    decision, option, opinion, subApplyInfo.getStatus().getValue(),
                    nextTaskHandlers,
                    subApplyInfo.isDispatched() ? WorkApplyOperationUtils.CREATE_SUB_FLOW_EXTENDS_DATA
                            : WorkApplyOperationUtils.NO_SUB_FLOW_EXTENDS_DATA, null);
            Preconditions.checkArgument(resultInfo != null && resultInfo.isResult(),
                    "uniflow完成任务失败!tiid：" + task.getTiid());
            if (resultInfo.getData() != null) {
                CollectionUtils.addAll(res, (TaskObject[]) resultInfo.getData());
            }
        }
        return res;
    }

    /**
     * 获取分任务的处理人.
     *
     * @param subApplyInfo 子工单信息
     * @return 处理人集合
     */
    public static UserInfo[] getSubApplyHandlers(final WorkApplyInfo subApplyInfo) {
        String assignUserId = subApplyInfo.getAssignUserId();
        String assignUserName = subApplyInfo.getAssignUserName();
        return getHandlerArray(assignUserId, assignUserName);
    }

    /**
     * 获取下一环节处理人.
     *
     * @param nextHandlerUid 下一处理人信息
     * @return 处理人集合
     */
    public static UserInfo[] getNextHandlers(final String nextHandlerUid) {
        List<UserInfo> userInfos = UserSelectItemUtils.convertToListUserSelectItem(nextHandlerUid).stream()
            .map(user -> new UserInfo(user.getUid(), user.getName(), user.getOrgShortName(), user.getOrgShortName())).collect(Collectors.toList());
        return userInfos.toArray(new UserInfo[0]);
    }

    /**
     * 获得办理人（主送人）UserInfo对象列表
     *
     * @param dispatchUserNames 办理人json
     * @return 工单的办理人（主送人）列表
     */
    public static List<List<UserInfo>> getReceiverUsers(final String dispatchUserNames) {
        // 先convertToListListUserSelectItem获得List<List<UserSelectItem>>，再转成List<List<UserInfo>>，这代码不写注释有几个看得懂？
        return UserSelectItemUtils.convertToListListUserSelectItem(dispatchUserNames).stream()
                .map(userList -> userList.stream().map(user -> new UserInfo(user.getUid(), user.getName(), user.getOrgShortName(), user.getOrgShortName())).collect(Collectors.toList()))
                .collect(Collectors.toList());
    }

    /**
     * 获得办理人（主送人）UserInfo对象列表的列表
     *
     * @param info 工单对象
     * @return 工单的办理人（主送人）列表的列表
     */
    public static List<List<UserInfo>> getReceiverUsers(final WorkApplyInfo info) {
        // 需要用receiverName去转
        return getReceiverUsers(info.getReceiverName());
    }

    /**
     * 全局锁.
     *
     * @param redisCacheUtil redis工具类
     * @param applyId        工单id
     * @param retryCount     重试次数
     * @param retryedCount   已重试次数
     * @param retryWaitTime  重试等待时间
     * @return 是/否
     */
    public static boolean lockWorkApplyInfo(final RedisCacheUtil redisCacheUtil, final String applyId,
                                            final int retryCount, final int retryedCount,
                                            final long retryWaitTime) {
        boolean res = false;
        try {
            if (retryedCount >= retryCount) {
                LOGGER.error("apply:{},已经超过最大重试次数{}", applyId, retryCount);
                return false;
            }
            if (retryedCount > 0) {
                //如果不是首次重试，则需要等待一段时间
                Thread.sleep(retryWaitTime);
            }
            res = redisCacheUtil.setNx(applyId, "1");
        } catch (InterruptedException e) {
            LOGGER.error("设置全局锁失败，applyId:{}", applyId, e);
            Thread.currentThread().interrupt();
        }
        if (res) {
            return true;
        }
        return lockWorkApplyInfo(redisCacheUtil, applyId, retryCount, retryedCount + 1, retryWaitTime);
    }

    /**
     * 获取用户对象.
     *
     * @param uid      uid
     * @param userName 用户名
     * @return 用户对象
     */
    public static UserInfo getUserInfo(final String uid, final String userName) {
        int index = userName.indexOf(" ");
        String nameTmp = userName;
        if (index != -1) {
            nameTmp = userName.substring(0, index);
        }
        return new UserInfo(uid, nameTmp);
    }

    /**
     * 任务记录，需要增加两条，一条自己，一条上级
     * @param workApplyInfoMapper
     * @param subTaskInfo
     * @param opinion
     * @param user
     * @param decision
     */
    public static void addTaskOpinion(final WorkApplyInfoMapper workApplyInfoMapper,final WorkSubTaskInfo subTaskInfo,
                                      final String opinion,final LoginUserPojo user,final String decision){
        WorkApproveOpinion opinionTask = buildApproveOpinionTask(
                opinion, user, subTaskInfo.getWorkApplyId(), decision, subTaskInfo.getNode().toString(), subTaskInfo.getId(),null);
        workApplyInfoMapper.insertWorkApproveOpinion(opinionTask);
        opinionTask.setWorkApplyId(subTaskInfo.getParentWorkApplyId());
        opinionTask.setId(UUID.randomUUID().toString());
        workApplyInfoMapper.insertWorkApproveOpinion(opinionTask);
    }

    public static void addOpinions(final WorkApplyInfoMapper workApplyInfoMapper, final Collection<WorkApplyInfo> infos,
                                   final String opinion, final LoginUserPojo user, final String decision){
        infos.forEach(workApplyInfo -> {
            WorkSubTaskInfo workSubTaskInfo = workApplyInfo.getSubTasks().get(0);
            addTaskOpinion(workApplyInfoMapper, workSubTaskInfo, opinion, user,
                    String.format("%s（%s:%s）", decision,workApplyInfo.getAssignUserName(), workSubTaskInfo.getName()));
        });
    }

    public static UserInfo[] getHandlerArray(final String userIds, final String userNames) {
        if (userIds.contains(Constants.STRING_SEMICOLON)) {
            return Streams.zip(Arrays.stream(StringUtils.split(userIds, Constants.STRING_SEMICOLON))
                , Arrays.stream(StringUtils.split(userNames, Constants.STRING_SEMICOLON))
                , (uid, name) -> new UserInfo(uid, name)).toArray(UserInfo[]::new);
        } else {
            return new UserInfo[]{new UserInfo(userIds, userNames)};
        }
    }

    /**
     * 是否主工单.
     * @param workApplyInfo 工单
     * @return 是否主工单
     */
    public static boolean isMainApply(final WorkApplyInfo workApplyInfo) {
        //主工单id
        final String mainWorkApplyId = workApplyInfo.getMainWorkApplyId();
        // 目前数据，主工单id为空或者主工单id等于id的为主工单
        return StringUtils.isBlank(mainWorkApplyId)
                || StringUtils.equals(workApplyInfo.getId(), mainWorkApplyId);
    }

    /**
     * 状态是否有工单操作权限.
     * @param workApplyInfo 工单
     * @param user 当前用户
     * @return
     */
    public static boolean haveOperatePermission(final WorkApplyInfo workApplyInfo, final LoginUserPojo user) {
        // 主工单
        if (isMainApply(workApplyInfo)) {
            return StringUtils.equals(workApplyInfo.getCreatorUid(), user.getUserID());
        }

        //子工单
        return Arrays.stream(workApplyInfo.getAssignUserId().split(Constants.STRING_SEMICOLON))
                .anyMatch(item -> StringUtils.equals(item, user.getUserID()));

    }
}
